#include "gtk-whiteboard.h"
#include <gdk/gdkkeysyms.h>

#include "window-properties.h"

GtkWhiteboard *
gtk_whiteboard_new()
{
	GtkWhiteboard *wb;
	GdkColor color;

	wb = g_malloc(sizeof(GtkWhiteboard));

	wb->drawing = gtk_drawing_area_new();
	gtk_widget_set_size_request(wb->drawing, 400, 400);
	wb->event = gtk_event_box_new();
	wb->scrolled = gtk_scrolled_window_new(FALSE, FALSE);
	wb->elements = NULL;
	wb->cur_shape = NULL;
	wb->sel_shape = NULL;
	wb->select_tool = FALSE;
	wb->arrow_tool = FALSE;

	wb->mouse_down = FALSE;

	gtk_widget_add_events(wb->drawing, GDK_ALL_EVENTS_MASK);
	GTK_WIDGET_SET_FLAGS (wb->drawing, GTK_CAN_FOCUS);
	g_signal_connect(wb->drawing, "expose-event", gtk_whiteboard_expose_event, wb);
	g_signal_connect(wb->drawing, "button-press-event", gtk_whiteboard_mouse_press_event, wb);
	g_signal_connect(wb->drawing, "button-release-event", gtk_whiteboard_mouse_release_event, wb);
	g_signal_connect_after(wb->drawing, "key-press-event", gtk_whiteboard_key_press_event, wb);
	g_signal_connect(wb->drawing, "motion-notify-event", gtk_whiteboard_mouse_move_event, wb);
	gdk_color_parse("white", &color);
	gtk_widget_modify_bg(wb->drawing,GTK_STATE_NORMAL, &color);
	gtk_container_add(wb->scrolled, wb->drawing);

	return wb;
}

shape_t *
gtk_whiteboard_shape_get_at(GtkWhiteboard *wb,
							double x,
							double y)
{
	GList *tmp = wb->elements;
	shape_t *shape = NULL;

	while (tmp) {
		shape = (shape_t *)tmp->data;
		if  ((x > shape->x) &&
			(y > shape->y)) {
			if ((x < (shape->x + shape->w)) &&
			    (y < (shape->y + shape->h))) {
					break;
			}
		}
		tmp = tmp->next;
	}
	if (!tmp)
		return NULL;
	return shape;
}

void
gtk_whiteboard_shape_delete(GtkWhiteboard *wb)
{
	GdkRectangle rect = {1, 1, 400, 400};

	if (wb->sel_shape) {
			wb->elements = g_list_remove(wb->elements, wb->sel_shape);
			wb->sel_shape == NULL;
			gdk_window_invalidate_rect(wb->drawing->window, &rect, TRUE);
		}
}

gboolean
gtk_whiteboard_key_press_event(GtkWidget *widget,
								 GdkEventKey *e,
								 gpointer data)
{
	GtkWhiteboard *wb = (GtkWhiteboard *)data;

	
	if (e->keyval == 65535 ||
	    e->keyval == GDK_Delete) {
		gtk_whiteboard_shape_delete(wb);
	}
	return FALSE;
}

gboolean
gtk_whiteboard_mouse_release_event(GtkWidget *widget,
								 GdkEventButton *e,
								 gpointer data)
{
	GtkWhiteboard *wb = (GtkWhiteboard *)data;
	wb->mouse_down = FALSE;

	return TRUE;
}
gboolean
gtk_whiteboard_mouse_press_event(GtkWidget *widget,
								 GdkEventButton *e,
								 gpointer data)
{
	GdkRectangle rect = {1, 1, 400, 400};
	shape_t *shape = g_malloc(sizeof(shape_t));
	GtkWhiteboard *wb = (GtkWhiteboard *)data;
	GList *tmp = wb->elements;
	
	wb->tmp_x = e->x;
	wb->tmp_y = e->y;

	wb->mouse_down = TRUE;
	gtk_widget_grab_focus(wb->drawing);
	if (wb->select_tool || wb->arrow_tool) {	
		while (tmp) {
			shape = (shape_t *)tmp->data;
			if  ((e->x > shape->x) &&
				(e->y > shape->y)) {
				if ((e->x < (shape->x + shape->w)) &&
				    (e->y < (shape->y + shape->h))) {
					printf("found shape %s\n", shape->ID);
					if (wb->sel_shape)
						wb->sel_shape->line_width = wb->sel_shape_line_width;
					wb->sel_shape_line_width = shape->line_width;
					//shape->line_width = 7.0;
					gdk_window_invalidate_rect(wb->drawing->window, &rect, TRUE);
					if (wb->arrow_tool) {
						if (wb->sel_shape) {
							printf("selecting the other shape ...\n");
							wb->sel_shape2 = shape;
							shape_conn_t *conn = g_malloc(sizeof(shape_conn_t));
							conn->shape_type = SHAPE_TYPE_ARROW_GENERIC;
							conn->from = wb->sel_shape;
							conn->to = wb->sel_shape2;
							wb->elements = g_list_append(wb->elements, conn);
							wb->arrow_tool = FALSE;
						} 
					} 
					wb->sel_shape = shape;

					break;
				}
			}
			tmp = tmp->next;
		}
		if (!tmp) { /* No shape was selected. */
			/* Unselect the previos shape, if any. */
			if (wb->sel_shape) {
				wb->sel_shape = NULL;
				gdk_window_invalidate_rect(wb->drawing->window, &rect, TRUE);
			}
		} else {
			if ((e->x >= (shape->x + (shape->w - 5))) &&
			    (e->x <= (shape->x + shape->w)) &&
				(e->y >= (shape->y + (shape->h - 5))) &&
				(e->y <= (shape->y + shape->h)))
				printf("Trying to resize\n");

			if (e->type == GDK_2BUTTON_PRESS) {
				window_properties_init(wb->drawing->window, wb->sel_shape);
			}
		}
	} else { /* Draw a new shape. */
		if (wb->cur_shape) {
			shape->d = wb->cur_shape->d;
			strcpy(shape->fill, wb->cur_shape->fill);
			shape->x = e->x;
			shape->shape_type = SHAPE_TYPE_PATH;
			shape->y = e->y;
			shape->conn_shape = NULL;
			shape->w = wb->cur_shape->w;
			shape->h = wb->cur_shape->h;
			shape->translate_x = wb->cur_shape->translate_x;
			shape->translate_y = wb->cur_shape->translate_y;
			shape->text = NULL;
			strcpy(shape->stroke, wb->cur_shape->stroke);
			strcpy(shape->ID, wb->cur_shape->ID);
			shape->line_width = wb->cur_shape->line_width;
			wb->elements = g_list_append(wb->elements, shape);
			gdk_window_invalidate_rect(widget->window, &rect, TRUE);
			wb->cur_shape = NULL;
		}
	}
	return TRUE;
}

gboolean
gtk_whiteboard_mouse_move_event(GtkWidget *widget,
								 GdkEventMotion *e,
								 gpointer data)

{
	GtkWhiteboard *wb = (GtkWhiteboard *)data;
	GdkRectangle rect = {1, 1, 400, 400};
	shape_t *shape;
	GdkCursor *cursor;

	shape = gtk_whiteboard_shape_get_at(wb, e->x, e->y);
	
	if (wb->select_tool) {
		if (shape)
		{
			cursor = gdk_cursor_new(GDK_FLEUR);
			gdk_window_set_cursor(wb->drawing->window, cursor);
		} else
			gdk_window_set_cursor(wb->drawing->window, NULL);
	}

	if (wb->mouse_down || wb->cur_shape) {
/*		if (wb->cur_shape) {
			wb->cur_shape->x = e->x;
			wb->cur_shape->y = e->y;
			wb->sel_shape = wb->cur_shape;
			wb->tmp_x = e->x+1;
			wb->tmp_y = e->y+1;
			wb->elements = g_list_append(wb->elements, wb->cur_shape);
		}*/
		if (wb->sel_shape) {
			if (e->x >= wb->tmp_x)
				wb->sel_shape->x += (e->x - wb->tmp_x);
			else
				wb->sel_shape->x -= (wb->tmp_x - e->x);
			if (e->y >= wb->tmp_y)
				wb->sel_shape->y += (e->y - wb->tmp_y);
			else
				wb->sel_shape->y -= (wb->tmp_y - e->y);
			wb->tmp_x = e->x;
			wb->tmp_y = e->y;
			gdk_window_invalidate_rect(wb->drawing->window, &rect, TRUE);
		}
	}

	return TRUE;
}

void
gtk_whiteboard_shape_select(GtkWhiteboard *wb,
							char *shape_id)
{
	shape_t *shape = NULL;
	GList *lib = shape_library;

	while (lib) {
		shape = (shape_t *)lib->data;
		if (strcmp(shape->ID, shape_id) == 0)
			break;
		lib = lib->next;
	}
	wb->cur_shape = shape;
}


void
gtk_whiteboard_connect(GtkWhiteboard *wb,
					   GCallback *click_cb,
					   gpointer click_data,
					   GCallback *move_cb,
					   gpointer move_data,
					   GCallback *key_pressed_cb,
					   gpointer key_pressed_data)
{

}

void
gtk_whiteboard_draw_elements(GtkWhiteboard *wb, GList *elements)
{
	cairo_t *c;
	GdkWindow *window = wb->drawing->window;
	shape_t *shape;
	GList *d;
	double a, b;
	GdkColor color;
	GdkColor color_stroke;
	c = gdk_cairo_create(window);

	cairo_select_font_face(c, "times", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(c, 14.0);

	while (elements != NULL) {
		shape = elements->data;
		d = shape->d;
		cairo_new_path(c);
		if (shape->shape_type == SHAPE_TYPE_ARROW_GENERIC) {
			shape_conn_t *connection = (shape_conn_t *)elements->data;
			double x, y, to_x, to_y;
			if (connection->to->x > connection->from->x) {
				x = connection->from->x + connection->from->w;
				y = connection->from->y + connection->from->h / 2;
				to_x = connection->to->x;
				to_y = connection->to->y + connection->to->h / 2;
			}
			else {
				x = connection->from->x;
				y = connection->from->y + connection->from->h / 2;
				to_x = connection->to->x + connection->to->w;
				to_y = connection->to->y + connection->to->h / 2;

			}
			if (connection->to->y > (connection->from->y + connection->from->h)) {
				y = connection->from->y + connection->from->h;
				x = connection->from->x + connection->from->w / 2;
				to_x = connection->to->x + connection->to->w / 2;
				to_y = connection->to->y;
			}
			else {
				y = connection->from->y;
				x = connection->from->x + connection->from->w / 2;
				to_x = connection->to->x + connection->to->w /2;
				to_y = connection->to->y + connection->to->h;
			}
			//x = connection->from->x + connection->from->w ;
			//y = connection->from->y + connection->from->h;
			cairo_move_to(c, x, y);
			cairo_set_source_rgb(c, 0.0, 0.0, 0.0);
			cairo_set_line_width(c, 1.0);
			cairo_line_to(c, to_x, to_y);
			cairo_new_sub_path(c);
			if (connection->to->y > connection->from->y) {
				cairo_move_to(c, to_x-5, to_y-5);
				cairo_line_to(c, to_x, to_y);
				cairo_move_to(c, to_x+5, to_y-5);
				cairo_line_to(c, to_x, to_y);
				cairo_move_to(c, to_x-5, to_y-5);
				cairo_line_to(c, to_x+5, to_y-5);

			} else {
				cairo_move_to(c, to_x-5, to_y+5);
				cairo_line_to(c, to_x, to_y);
				cairo_move_to(c, to_x+5, to_y+5);
				cairo_line_to(c, to_x, to_y);
				cairo_move_to(c, to_x-5, to_y+5);
				cairo_line_to(c, to_x+5, to_y+5);
			}
			cairo_fill_preserve(c);

			cairo_close_path(c);
			cairo_fill_preserve(c);
			cairo_stroke(c);
		}
		else if (shape->shape_type == SHAPE_TYPE_PATH) {
			gdk_color_parse(shape->fill, &color);
			gdk_color_parse(shape->stroke, &color_stroke);
			gdk_cairo_set_source_color(c, &color_stroke);

			cairo_set_line_width(c, shape->line_width);
		

			while (d != NULL) {
				if (strcmp(d->data, "M") == 0) {
					d = d->next;
					/* TODO: fix this. */
					get_coords_from_string((char *)d->data, &a, &b);
					cairo_move_to(c, (shape->x + a) + shape->translate_x, (shape->y + b) + shape->translate_y);
				}
				else if (strcmp(d->data, "L") == 0) {
					d = d->next;
					get_coords_from_string((char *)d->data, &a, &b);
					cairo_line_to(c, (shape->x + a) + shape->translate_x, (shape->y + b) + shape->translate_y);
					cairo_stroke_preserve(c);
				}
				else if (strcmp(d->data, "z") == 0) {
					cairo_close_path(c);	
					gdk_cairo_set_source_color(c, &color);
					cairo_fill(c);
				}
				d = d->next;
			}

			if (shape->text) {
				cairo_move_to(c, shape->x + shape->line_width, shape->y + (shape->h / 2));
				cairo_set_source_rgb(c, 0.0, 0.0, 0.0);
				cairo_show_text(c, shape->text);
			}
		}
		
		if (wb->sel_shape) {
			cairo_set_line_width(c, 1.0);
			cairo_set_source_rgb(c, 1.0, 0.0, 0.0);
			cairo_rectangle(c, wb->sel_shape->x, wb->sel_shape->y, wb->sel_shape->w, wb->sel_shape->h);
			/* A small rect in buttom right corner. */
			cairo_rectangle(c, wb->sel_shape->x + wb->sel_shape->w - 5, wb->sel_shape->y + wb->sel_shape->h - 5, 4, 4);
		}
		//printf("w: %f, h: %f\n", shape->w, shape->h);
		elements = elements->next;
	}
	cairo_stroke(c);
	cairo_destroy(c);
}

gboolean
gtk_whiteboard_expose_event(GtkWidget *widget,
							GdkEventExpose *e,
							gpointer data)
{
	GtkWhiteboard *wb = (GtkWhiteboard *)data;
	GList *elements = NULL;
	/*
	 * TODO: here goes the whiteboard drawing function.
	 */

//	if (wb->cur_shape)
//		elements = g_list_append(elements, wb->cur_shape);
//	else
		elements = wb->elements;
	gtk_whiteboard_draw_elements(wb, elements);
	return TRUE;
}

void
gtk_whiteboard_destroy(GtkWhiteboard *wb)
{
	gtk_widget_destroy(wb->drawing);
	gtk_widget_destroy(wb->event);

	g_free(wb);
}

